package com.huirui.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huirui.server.constant.ProductType;
import com.huirui.server.context.UserContext;
import com.huirui.server.exception.ProductInsertException;
import com.huirui.server.exception.ProductNotExistsException;
import com.huirui.server.exception.ProductRemovedException;
import com.huirui.server.mapper.ProductMapper;
import com.huirui.server.pojo.dto.ProductDto;
import com.huirui.server.pojo.entity.*;
import com.huirui.server.pojo.result.PageResult;
import com.huirui.server.pojo.vo.*;
import com.huirui.server.service.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yujun
 * @description 针对表【t_product(商品主表)】的数据库操作Service实现
 * @createDate 2025-09-16 18:02:04
 */
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
        implements ProductService {

    @Resource
    private BrowseHistoryService browseHistoryService;

    @Resource
    private ProductSpecificationService specificationService;

    @Resource
    private ProductCategoryRelationService productCategoryRelationService;

    @Autowired
    private ProductSpecificationService productSpecificationService;

    @Autowired
    private ProductParameterService productParameterService;
    @Autowired
    private CategoryService categoryService;

    @Resource
    private SeckillService seckillService;

    @Resource
    private BrandService brandService;


    @Override
    public IPage<ProductBriefInfoVo> listProductsByComprehensive(String keyword, Page<ProductBriefInfoVo> pageParam) {
        return baseMapper.selectProductsByComprehensive(keyword, pageParam);
    }

    @Override
    public IPage<ProductBriefInfoVo> listProductsBySales(String keyword, Page<ProductBriefInfoVo> pageParam) {
        return baseMapper.selectProductsBySales(keyword, pageParam);
    }

    @Override
    public IPage<ProductBriefInfoVo> listProductsByTime(String keyword, Page<ProductBriefInfoVo> pageParam) {
        return baseMapper.selectProductsByTime(keyword, pageParam);
    }

    @Override
    public IPage<ProductBriefInfoVo> listProductsByPrice(String keyword, String orderBy, Page<ProductBriefInfoVo> pageParam) {
        return baseMapper.selectProductsByPrice(keyword, orderBy, pageParam);
    }

    @Override
    public ProductDetailVo getProductDetailInfoByProductId(Long id) {

        // 首先查询商品是否存在
        boolean exists = lambdaQuery().eq(Product::getId, id).exists();
        if (!exists) {
            throw new ProductNotExistsException("商品不存在");
        }

        // 首先查询商品状态
        Integer productStatus = lambdaQuery()
                .select(Product::getProductStatus)
                .eq(Product::getId, id)
                .one().getProductStatus();
        if (productStatus == 2) {
            throw new ProductRemovedException("商品已下架");
        }

        // 保存浏览历史
        if (UserContext.getId() != null) {
            // 首先查询是否当前浏览过该商品
            LocalDateTime start = LocalDate.now().atStartOfDay();
            LocalDateTime end = LocalDate.now().plusDays(1).atStartOfDay().minusNanos(1);
            Optional<BrowseHistory> optionalBrowseHistory = browseHistoryService
                    .lambdaQuery()
                    .eq(BrowseHistory::getUserId, UserContext.getId())
                    .eq(BrowseHistory::getProductId, id)
                    .ge(BrowseHistory::getBrowseTime, start)
                    .le(BrowseHistory::getBrowseTime, end)
                    .oneOpt();
            // 如果存在，删除该条记录
            optionalBrowseHistory.ifPresent(browseHistory -> browseHistoryService.removeById(browseHistory.getId()));
            // 保存商品的浏览记录
            Long userId = UserContext.getId();
            BrowseHistory browseHistory = new BrowseHistory();
            browseHistory.setProductId(id);
            browseHistory.setBrowseTime(LocalDateTime.now());
            browseHistory.setUserId(userId);
            browseHistoryService.save(browseHistory);
        }

        Product product = lambdaQuery()
                .select(Product::getProductName,
                        Product::getBrandId,
                        Product::getProductTip,
                        Product::getProductType,
                        Product::getBannerImageUrls,
                        Product::getDetailImageUrls,
                        Product::getBrandId,
                        Product::getId)
                .eq(Product::getId, id)
                .one();

        ProductDetailVo productDetailVo = BeanUtil.copyProperties(product, ProductDetailVo.class);
        // 查询商品品牌
        Brand brand = brandService
                .lambdaQuery()
                .select(Brand::getBrandName)
                .eq(Brand::getId, product.getBrandId())
                .one();
        productDetailVo.setBrandId(product.getBrandId());
        productDetailVo.setBrandName(brand == null ? null : brand.getBrandName());
        // 如果是秒杀商品的话，需要查询秒杀时间
        if (product.getProductType() == ProductType.SECKILL_PRODUCT) {
            SeckillVo relation = seckillService.getSeckillProductById(id);
            // 秒杀商品未启用！
            if (relation.getStatus() == 1) {
                product.setProductType(ProductType.GENERAL_PRODUCT);
            } else {
                productDetailVo.setAvailableStock(relation.getAvailableStock());
                productDetailVo.setStock(relation.getStock());
                productDetailVo.setSeckillStartTime(relation.getSeckillStartTime());
                productDetailVo.setSeckillEndTime(relation.getSeckillEndTime());
            }
        }
        // 如果是临期商品，需要查询生产日期
        if (product.getProductType() == ProductType.SHORT_DATED_PRODUCT) {
            ProductParameter one = productParameterService
                    .lambdaQuery()
                    .eq(ProductParameter::getProductId, id)
                    .select(ProductParameter::getManufacturingDate, ProductParameter::getExpiryDate)
                    .one();
            productDetailVo.setManufactureDate(one.getManufacturingDate());
            productDetailVo.setExpirationDate(one.getExpiryDate());
        }
        List<ProductSpecificationVo> specificationVoList = specificationService
                .lambdaQuery()
                .select(ProductSpecification::getIsDefault,
                        ProductSpecification::getDiscountPrice,
                        ProductSpecification::getOriginalPrice,
                        ProductSpecification::getSeckillPrice,
                        ProductSpecification::getSpecificationName,
                        ProductSpecification::getStock,
                        ProductSpecification::getPromotionalPrice,
                        ProductSpecification::getSpecificationImageUrl,
                        ProductSpecification::getId)
                .eq(ProductSpecification::getProductId, id)
                .orderByDesc(ProductSpecification::getIsDefault)
                .orderByDesc(ProductSpecification::getSpecificationSort)
                .orderByDesc(ProductSpecification::getUpdateTime)
                .list()
                .stream()
                .map(productSpecification ->
                        ProductSpecificationVo.builder()
                                .seckillPrice(productSpecification.getSeckillPrice())
                                .specificationName(productSpecification.getSpecificationName())
                                .specificationImageUrl(productSpecification.getSpecificationImageUrl())
                                .discountPrice(productSpecification.getDiscountPrice())
                                .originalPrice(productSpecification.getOriginalPrice())
                                .isDefault(productSpecification.getIsDefault())
                                .promotionPrice(productSpecification.getPromotionalPrice())
                                .stock(productSpecification.getStock())
                                .id(productSpecification.getId())
                                .build()
                )
                .toList();
        productDetailVo.setSpecificationVoList(specificationVoList);
        return productDetailVo;
    }

    @Override
    public List<ProductBriefInfoVo> listProductBriefInfoVoByIds(List<Long> ids) {
        if (ids.isEmpty()) {
            return List.of();
        }
        return baseMapper.listProductBriefInfoVoByIds(ids);
    }

    @Override
    public IPage<ProductBriefInfoVo> listBestseller(Long page, Long pageSize) {
        Page<ProductBriefInfoVo> iPage = new Page<>(page, pageSize);
        return baseMapper.listBestseller(iPage);
    }

    @Override
    public PageResult<ProductVo> getProductList(String option, Long page, Long pageSize) {
        IPage<ProductVo> iPage = new Page<>(page, pageSize);
        iPage = baseMapper.getProductList(option, iPage);
        return PageResult.from(iPage);
    }

    @Override
    @Transactional
    public void saveProduct(ProductDto productDto) {
        // 处理可能的重复插入情况
        boolean flag = lambdaQuery()
                .eq(Product::getProductName, productDto.getProductName())
                .exists();
        if (flag) throw new ProductNotExistsException("该商品已存在，请勿重复插入");
        // 插入主表
        Product product = new Product();
        product.setCreateTime(LocalDateTime.now());
        product.setUpdateTime(LocalDateTime.now());
        product.setProductName(productDto.getProductName());
        product.setProductTip(productDto.getTip());
        product.setProductStatus(productDto.getStatus());
        product.setBrandId(productDto.getBrandId());
        product.setMainImageUrl(productDto.getProductImage());
        product.setProductStatus(productDto.getStatus());
        product.setWeight(Math.toIntExact(productDto.getWeight()));
        product.setInventoryCountingMethod(productDto.getInventoryCountingMethod());
        product.setBannerImageUrls(StringUtils.join(productDto.getBannerImages(), ','));
        product.setDetailImageUrls(StringUtils.join(productDto.getDetailImages(), ','));
        save(product);
        // 保存分类信息
        List<Long> categoryIds = productDto.getCategoryIds();
        final var productId = product.getId();
        List<ProductCategoryRelation> productCategoryRelationList = new ArrayList<>(categoryIds.size());
        for (Long categoryId : categoryIds) {
            ProductCategoryRelation productCategoryRelation = new ProductCategoryRelation();
            productCategoryRelation
                    .setProductId(productId)
                    .setCategoryId(categoryId);
            productCategoryRelationList.add(productCategoryRelation);
        }
        productCategoryRelationService.saveBatch(productCategoryRelationList);
        // 保存商品规格信息
        List<ProductSpecification> productSpecificationList = new ArrayList<>();
        List<ProductDto.ProductSpecificationDto> productSpecificationDtoList = productDto.getProductSpecificationDtoList();
        productSpecificationDtoList.sort(Comparator.comparingInt(ProductDto.ProductSpecificationDto::getSort));
        productSpecificationDtoList
                .forEach(productSpecificationDto -> {
                    ProductSpecification specification = new ProductSpecification();
                    specification
                            .createTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .productId(productId)
                            .specificationSort(productSpecificationDto.getSort())
                            .stock(Math.toIntExact(productSpecificationDto.getStock()))
                            .availableStock(Math.toIntExact(productSpecificationDto.getStock()))
                            .saleCount(productDto.getInitialSalesVolume() / productSpecificationDtoList.size())
                            .specificationName(productSpecificationDto.getProductSpecificationName())
                            .isDefault(productSpecificationDto.equals(productSpecificationDtoList.getFirst()) ? 1 : 0)
                            .originalPrice(
                                    BigDecimal.valueOf(
                                            productSpecificationDto
                                                    .getOriginalPrice() > productSpecificationDto
                                                    .getDiscountPrice() ? productSpecificationDto
                                                    .getOriginalPrice() : productSpecificationDto.getDiscountPrice()
                                    )
                            )
                            .discountPrice(BigDecimal.valueOf(productSpecificationDto.getDiscountPrice()));
                    if (!StringUtils.isBlank(productSpecificationDto.getProductSpecificationImage())) {
                        specification.specificationImageUrl(productSpecificationDto.getProductSpecificationImage());
                    } else {
                        specification.specificationImageUrl(product.getMainImageUrl());
                    }
                    productSpecificationList.add(specification);
                });
        productSpecificationService.saveBatch(productSpecificationList);
        // 保存商品的规格信息
        ProductParameter productParameter = new ProductParameter();
        productParameter.setProductId(productId);
        productParameter.setCreateTime(LocalDateTime.now());
        productParameter.setUpdateTime(LocalDateTime.now());
        productParameter.setManufacturingEnterprise(productDto.getManufacturingEnterprise());
        productParameter.setRegistrationNumber(productDto.getRegistrationNumber());
        productParameter.setRegistrationIdPhoto(productDto.getRegistrationIdPhoto());
        productParameter.setMedicalInsuranceNumber(productDto.getMedicalInsuranceNumber());
        productParameter.setProductPackaging(productDto.getProductPackaging());
        productParameter.setExpiryDate(productDto.getExpiryDate());
        productParameter.setManufacturingDate(productDto.getManufacturingDate());
        productParameterService.save(productParameter);
    }

    @Override
    @Transactional
    public void deleteProductById(Long id) {
        boolean exists = lambdaQuery()
                .eq(Product::getId, id)
                .exists();
        if (!exists) {
            throw new ProductNotExistsException("商品不存在");
        }
        // 删除商品
        removeById(id);
        // 删除商品规格
        Map<String, Object> map = new HashMap<>();
        map.put("product_id", id);
        productSpecificationService
                .removeByMap(map);
        // 删除商品参数
        productParameterService
                .lambdaUpdate()
                .eq(ProductParameter::getProductId, id)
                .remove();
        // 删除商品分类关系
        productCategoryRelationService
                .lambdaUpdate()
                .eq(ProductCategoryRelation::getProductId, id)
                .remove();
    }

    @Override
    public ProductEditVo productEcho(Long id) {
        Product product = lambdaQuery()
                .eq(Product::getId, id)
                .one();
        if (product == null) {
            throw new ProductNotExistsException("商品不存在");
        }

        ProductParameter productParameter = productParameterService
                .lambdaQuery()
                .eq(ProductParameter::getProductId, id)
                .one();
        List<ProductSpecification> productSpecificationList = productSpecificationService
                .lambdaQuery()
                .eq(ProductSpecification::getProductId, id)
                .orderByDesc(ProductSpecification::getIsDefault)
                .orderByDesc(ProductSpecification::getSpecificationSort)
                .list();
        List<ProductCategoryRelation> relationList = productCategoryRelationService
                .lambdaQuery()
                .eq(ProductCategoryRelation::getProductId, id)
                .list();
        ProductEditVo productEditVo = new ProductEditVo();
        productEditVo
                .setProductId(id)
                .setProductName(product.getProductName())
                .setProductDescription(product.getProductTip())
                .setCategoryIds(
                        relationList
                                .stream()
                                .map(ProductCategoryRelation::getCategoryId)
                                .toList()
                )
                .setProductImage(product.getMainImageUrl())
                .setProductStatus(product.getProductStatus())
                .setWeight(product.getWeight())
                .setBannerImages(
                        Arrays.asList(product.getBannerImageUrls().split(","))
                )
                .setDetailImages(
                        Arrays.asList(product.getDetailImageUrls().split(","))
                )
                .setManufacturingEnterprise(productParameter.getManufacturingEnterprise())
                .setBrandId(product.getBrandId())
                .setProductPackaging(productParameter.getProductPackaging())
                .setRegistrationNumber(productParameter.getRegistrationNumber())
                .setMedicalInsuranceNumber(productParameter.getMedicalInsuranceNumber())
                .setRegistrationIdPhoto(productParameter.getRegistrationIdPhoto())
                .setManufacturingDate(productParameter.getManufacturingDate())
                .setExpiryDate(productParameter.getExpiryDate())
                .setInventoryCountingMethod(product.getInventoryCountingMethod());
        List<ProductEditVo.ProductSpecificationVo> productSpecificationVoList = new ArrayList<>();
        productSpecificationList.forEach(productSpecification -> {
            ProductEditVo.ProductSpecificationVo productSpecificationVo = new ProductEditVo.ProductSpecificationVo();
            productSpecificationVo.setProductSpecificationId(productSpecification.getId());
            productSpecificationVo.setProductSpecificationImage(productSpecification.getSpecificationImageUrl());
            productSpecificationVo.setProductSpecificationName(productSpecification.getSpecificationName());
            productSpecificationVo.setSort(productSpecification.getSpecificationSort());
            productSpecificationVo.setStock(Long.valueOf(productSpecification.getAvailableStock()));
            productSpecificationVo.setDiscountPrice(productSpecification.getDiscountPrice().doubleValue());
            productSpecificationVo.setOriginalPrice(productSpecification.getOriginalPrice().doubleValue());
            productSpecificationVo.setSaleCount(productSpecification.getSaleCount());
            productSpecificationVo.setPromotionalPrice(productSpecification.getPromotionalPrice());
            productSpecificationVo
                    .setSeckillPrice(productSpecification.getSeckillPrice() == null ? productSpecification.getDiscountPrice().doubleValue() : productSpecification.getSeckillPrice().doubleValue());
            productSpecificationVoList.add(productSpecificationVo);
        });
        productEditVo.setProductSpecifications(productSpecificationVoList);
        return productEditVo;
    }

    @Override
    @Transactional
    public void updateProduct(ProductDto productDto) {
        Long productId = productDto.getId();
        boolean exists = lambdaQuery()
                .eq(Product::getId, productId)
                .exists();
        if (!exists) {
            throw new ProductNotExistsException("商品不存在");
        }
        // 更新商品主表
        lambdaUpdate()
                .eq(Product::getId, productId)
                .set(
                        StringUtils.isNotBlank(productDto.getProductName()),
                        Product::getProductName,
                        productDto.getProductName()
                )
                .set(
                        StringUtils.isNotBlank(productDto.getTip()),
                        Product::getProductTip,
                        productDto.getTip()
                )
                .set(
                        StringUtils.isNotBlank(productDto.getProductImage()),
                        Product::getMainImageUrl,
                        productDto.getProductImage()
                )
                .set(
                        ObjectUtils.isNotEmpty(productDto.getStatus()),
                        Product::getProductStatus,
                        productDto.getStatus()
                )
                .set(
                        ObjectUtils.isNotEmpty(productDto.getWeight()),
                        Product::getWeight,
                        productDto.getWeight()
                )
                .set(
                        ObjectUtils.isNotEmpty(productDto.getInventoryCountingMethod()),
                        Product::getInventoryCountingMethod,
                        productDto.getInventoryCountingMethod()
                )
                .set(
                        CollectionUtil.isNotEmpty(productDto.getBannerImages()),
                        Product::getBannerImageUrls,
                        StringUtils.join(productDto.getBannerImages(), ","))
                .set(
                        CollectionUtil.isNotEmpty(productDto.getDetailImages()),
                        Product::getDetailImageUrls,
                        StringUtils.join(productDto.getDetailImages(), ",")
                )
                .set(
                        Product::getBrandId,
                        productDto.getBrandId()
                )
                .set(Product::getUpdateTime, LocalDateTime.now())
                .update();
        // 更新商品分类关系表
        productCategoryRelationService
                .lambdaUpdate()
                .eq(ProductCategoryRelation::getProductId, productId)
                .remove();
        if (productDto.getCategoryIds() == null) {
            throw new ProductInsertException("商品分类ID不能为空");
        }
        List<ProductCategoryRelation> relationList = new ArrayList<>();
        for (Long categoryId : productDto.getCategoryIds()) {
            ProductCategoryRelation productCategoryRelation = new ProductCategoryRelation();
            productCategoryRelation.setCategoryId(categoryId);
            productCategoryRelation.setProductId(productId);
            relationList.add(productCategoryRelation);
        }
        productCategoryRelationService.saveBatch(relationList);
        // 更新商品参数表
        productParameterService
                .lambdaUpdate()
                .eq(ProductParameter::getProductId, productId)
                .set(
                        StringUtils.isNotBlank(productDto.getManufacturingEnterprise()),
                        ProductParameter::getManufacturingEnterprise,
                        productDto.getManufacturingEnterprise()
                )
                .set(
                        StringUtils.isNotBlank(productDto.getRegistrationNumber()),
                        ProductParameter::getRegistrationNumber,
                        productDto.getRegistrationNumber()
                )
                .set(
                        StringUtils.isNotBlank(productDto.getMedicalInsuranceNumber()),
                        ProductParameter::getMedicalInsuranceNumber,
                        productDto.getMedicalInsuranceNumber()
                )
                .set(
                        ProductParameter::getRegistrationIdPhoto,
                        productDto.getRegistrationIdPhoto()
                )
                .set(
                        StringUtils.isNotBlank(productDto.getProductPackaging()),
                        ProductParameter::getProductPackaging,
                        productDto.getProductPackaging()
                )
                .set(
                        ObjectUtils.isNotEmpty(productDto.getManufacturingDate()),
                        ProductParameter::getManufacturingDate,
                        productDto.getManufacturingDate()
                )
                .set(
                        ObjectUtils.isNotEmpty(productDto.getExpiryDate()),
                        ProductParameter::getExpiryDate,
                        productDto.getExpiryDate()
                )
                .set(ProductParameter::getUpdateTime, LocalDateTime.now())
                .update();
        // 更新商品规格表
        List<ProductDto.ProductSpecificationDto> productSpecificationDtoList = productDto.getProductSpecificationDtoList();
        if (CollectionUtil.isEmpty(productSpecificationDtoList)) {
            throw new ProductInsertException("商品规格不能为空");
        }
        productSpecificationDtoList.sort(Comparator.comparingInt(ProductDto.ProductSpecificationDto::getSort));
        Set<Long> oldSpecificationIds = productSpecificationService
                .lambdaQuery()
                .select(ProductSpecification::getId)
                .eq(ProductSpecification::getProductId, productId)
                .list()
                .stream()
                .map(ProductSpecification::getId)
                .collect(Collectors.toSet());

        HashSet<String> set = new HashSet<>();
        productSpecificationDtoList.forEach(productSpecificationDto -> {
            if (set.contains(productSpecificationDto.getProductSpecificationName())) {
                throw new ProductInsertException("规格名不可以重复");
            }
            set.add(productSpecificationDto.getProductSpecificationName());
            if (productSpecificationDto.getId() == null) {
                // 插入操作
                ProductSpecification productSpecification = new ProductSpecification();
                productSpecification.setProductId(productId);
                productSpecification.setSpecificationName(productSpecificationDto.getProductSpecificationName());
                if (StringUtils.isBlank(productSpecificationDto.getProductSpecificationImage())) {
                    productSpecification.setSpecificationImageUrl(productDto.getProductImage());
                }
                productSpecification.setDiscountPrice(BigDecimal.valueOf(productSpecificationDto.getDiscountPrice()));
                productSpecification.setOriginalPrice(
                        BigDecimal.valueOf(
                                productSpecificationDto
                                        .getOriginalPrice() > productSpecificationDto
                                        .getDiscountPrice() ? productSpecificationDto
                                        .getOriginalPrice() : productSpecificationDto.getDiscountPrice()
                        )
                );
                productSpecification.setSaleCount(productSpecificationDto.getSaleCount());
                productSpecification.setSpecificationSort(productSpecificationDto.getSort());
                productSpecification.setStock(Math.toIntExact(productSpecificationDto.getStock()));
                productSpecification.setAvailableStock(Math.toIntExact(productSpecificationDto.getStock()));
                productSpecification.setCreateTime(LocalDateTime.now());
                productSpecification.setUpdateTime(LocalDateTime.now());
                productSpecification.setIsDefault(productSpecificationDto.equals(productSpecificationDtoList.getFirst()) ? 1 : 0);
                productSpecificationService.save(productSpecification);
            } else {
                oldSpecificationIds.remove(productSpecificationDto.getId());
                productSpecificationService
                        .lambdaUpdate()
                        .eq(ProductSpecification::getId, productSpecificationDto.getId())
                        .set(
                                StringUtils.isNotBlank(productSpecificationDto.getProductSpecificationName()),
                                ProductSpecification::getSpecificationName,
                                productSpecificationDto.getProductSpecificationName()
                        )
                        .set(
                                ProductSpecification::getSpecificationImageUrl,
                                StringUtils
                                        .isBlank(productSpecificationDto.getProductSpecificationImage()) ?
                                        productDto.getProductImage() :
                                        productSpecificationDto.getProductSpecificationImage()
                        )
                        .set(
                                ProductSpecification::getDiscountPrice,
                                productSpecificationDto.getDiscountPrice()
                        )
                        .set(
                                ProductSpecification::getOriginalPrice,
                                BigDecimal.valueOf(
                                        productSpecificationDto
                                                .getOriginalPrice() > productSpecificationDto
                                                .getDiscountPrice() ? productSpecificationDto
                                                .getOriginalPrice() : productSpecificationDto.getDiscountPrice()
                                )
                        )
                        .set(
                                ProductSpecification::getStock,
                                productSpecificationDto.getStock()
                        )
                        .set(
                                ProductSpecification::getAvailableStock,
                                productSpecificationDto.getStock()
                        )
                        .set(
                                ProductSpecification::getSaleCount,
                                productSpecificationDto.getSaleCount()
                        )
                        .set(
                                ProductSpecification::getIsDefault,
                                productSpecificationDto.equals(productSpecificationDtoList.getFirst()) ? 1 : 0
                        )
                        .set(
                                ProductSpecification::getSpecificationSort,
                                productSpecificationDto.getSort()
                        )
                        .set(ProductSpecification::getUpdateTime, LocalDateTime.now())
                        .update();
            }
        });
        if (!oldSpecificationIds.isEmpty()) {
            productSpecificationService
                    .lambdaUpdate()
                    .in(ProductSpecification::getId, oldSpecificationIds)
                    .remove();
        }
    }

    @Override
    public PageResult<ProductVo> searchProduct(String productName, String productCode, String status, Long categoryId, Long productType, Long page, Long pageSize) {
        IPage<ProductVo> ipage = new Page<>(page, pageSize);
        // 首先获取id列表
        Set<Long> categoryIds;
        if (categoryId != null) {
            categoryIds = new HashSet<>();
            categoryIds.add(categoryId);
            int level = categoryService
                    .lambdaQuery()
                    .select(Category::getLevel)
                    .eq(Category::getId, categoryId)
                    .oneOpt()
                    .map(Category::getLevel)
                    .orElse(-1);
            if (level == 1) {
                // 一级分类需查询所有子分类
                categoryIds
                        .addAll(categoryService
                                .lambdaQuery()
                                .select(Category::getId)
                                .eq(Category::getParentId, categoryId)
                                .list()
                                .stream().map(Category::getId).toList()
                        );
                categoryIds.addAll(
                        categoryService.lambdaQuery()
                                .select(Category::getId)
                                .in(Category::getParentId, categoryIds)
                                .list()
                                .stream().map(Category::getId).toList()
                );
            } else if (level == 2) {
                categoryIds.addAll(
                        categoryService
                                .lambdaQuery()
                                .eq(Category::getParentId, categoryId)
                                .select(Category::getId)
                                .list()
                                .stream()
                                .map(Category::getId)
                                .toList()
                );
            } else if (level == 3) {
                categoryIds.add(categoryId);
            } else if (level == -1) {
                categoryIds = null;
            }
        } else {
            categoryIds = null;
        }
        ipage = baseMapper.searchProduct(productName, productCode, status, categoryIds, productType, ipage);
        return PageResult.from(ipage);
    }

    @Override
    public List<SimpleProductVo> searchBriefProductInfo(String keyword) {
        return baseMapper.searchBriefProductInfo(keyword);
    }

    @Override
    public List<CouponProductVo> listCouponProductInfo(List<Long> productIds) {
        return baseMapper.listCouponProductInfo(productIds);
    }

    @Override
    public List<SeckillProductVo> listSeckillProductInfoByProductIds(List<Long> productIds) {
        if (productIds == null || productIds.isEmpty()) {
            return new ArrayList<>();
        }
        return baseMapper.listSeckillProductInfoByProductIds(productIds);
    }

    @Override
    public List<HotSalesRankingProductVo> getHotSalesRankingProducts(Integer id) {
        return baseMapper
                .getHotSalesRankingProducts(id)
                .stream().sorted(Comparator.comparing(HotSalesRankingProductVo::getSaleCount).reversed())
                .collect(Collectors.toList());
    }

    @Override
    public PageResult<HomePageProductVo> listHomePageProduct(Long categoryId, Long page, Long pageSize) {
        if (categoryId != -1) {
            // 首先根据分类ID查询所有的三级分类
            List<Long> secondaryCategoryList = categoryService
                    .lambdaQuery()
                    .select(Category::getId)
                    .eq(Category::getParentId, categoryId)
                    .list()
                    .stream()
                    .map(Category::getId)
                    .toList();
            List<Long> threeLevelCategoryIdList = categoryService
                    .lambdaQuery()
                    .select(Category::getId)
                    .in(!secondaryCategoryList.isEmpty(), Category::getParentId, secondaryCategoryList)
                    .list()
                    .stream()
                    .map(Category::getId)
                    .toList();
            IPage<HomePageProductVo> ipage = new Page<>(page, pageSize);
            ipage = baseMapper.listHomePageProduct(threeLevelCategoryIdList, ipage);
            return PageResult.from(ipage);
        } else {
            IPage<HomePageProductVo> ipage = new Page<>(page, pageSize);
            ipage = baseMapper.personalizedListHomePageProduct(ipage);
            return PageResult.from(ipage);
        }
    }

    @Override
    public PageResult<ProductEchoVo> listProduct(Integer searchType, Integer sort, String keyword, Long page, Long pageSize) {
        IPage<ProductEchoVo> iPage = new Page<>(page, pageSize);
        if (searchType == 0) {
            // 关键词搜索
            if (sort == 0) {
                // 综合搜索
                iPage = baseMapper.listProductByKeyWordAndComprehensive(keyword, iPage);

            } else if (sort == 1) {
                // 销量搜索
                iPage = baseMapper.listProductByKeyWordAndSalesAmount(keyword, iPage);

            } else if (sort == 2) {
                // 价格从低到高
                iPage = baseMapper.listProductByKeyWordAndPriceAsc(keyword, iPage);
            } else if (sort == 3) {
                // 价格从高到底
                iPage = baseMapper.listProductByKeyWordAndPriceDesc(keyword, iPage);

            } else if (sort == 4) {
                // 上架时间
                iPage = baseMapper.listProductByKeyWordAndDateIssued(keyword, iPage);

            }
        } else if (searchType == 1) {
            // 安装分类查询，可能是二级分类，也可能是三级分类
            List<Long> categoryIds = new ArrayList<>();
            Long categoryId = Long.valueOf(keyword);
            categoryIds.add(categoryId);
            Integer level = categoryService
                    .lambdaQuery()
                    .select(Category::getLevel)
                    .eq(Category::getId, categoryId)
                    .one()
                    .getLevel();
            if (level == 2) {
                List<Long> list = categoryService
                        .lambdaQuery()
                        .select(Category::getId)
                        .eq(Category::getParentId, categoryId)
                        .list()
                        .stream()
                        .map(Category::getId)
                        .toList();
                categoryIds.addAll(list);
            }

            // 分类搜索
            if (sort == 0) {
                // 综合搜索
                iPage = baseMapper.listProductByCategoryIdsAndComprehensive(categoryIds, iPage);

            } else if (sort == 1) {
                // 销量搜索
                iPage = baseMapper.listProductByCategoryIdsAndSalesAmount(categoryIds, iPage);

            } else if (sort == 2) {
                // 价格从低到高
                iPage = baseMapper.listProductByCategoryIdsAndPriceAsc(categoryIds, iPage);

            } else if (sort == 3) {
                // 价格从高到底
                iPage = baseMapper.listProductByCategoryIdsAndPriceDesc(categoryIds, iPage);

            } else if (sort == 4) {
                // 上架时间
                iPage = baseMapper.listProductByCategoryIdsAndDateIssued(categoryIds, iPage);

            }
        } else if (searchType == 2) {
            // 品牌搜索
            if (sort == 0) {
                // 综合搜索
                iPage = baseMapper.listProductByBrandIdAndComprehensive(Long.valueOf(keyword), iPage);

            } else if (sort == 1) {
                // 销量搜索
                iPage = baseMapper.listProductByBrandIdAndSalesAmount(Long.valueOf(keyword), iPage);

            } else if (sort == 2) {
                // 价格从低到高
                iPage = baseMapper.listProductByBrandIdAndPriceAsc(Long.valueOf(keyword), iPage);

            } else if (sort == 3) {
                // 价格从高到底
                iPage = baseMapper.listProductByBrandIdAndPriceDesc(Long.valueOf(keyword), iPage);

            } else if (sort == 4) {
                // 上架时间
                iPage = baseMapper.listProductByBrandIdAndDateIssued(Long.valueOf(keyword), iPage);

            }
        }
        return PageResult.from(iPage);
    }

    @Override
    public PageResult<ProductListInfoVo> listProduct(String productName, String brandName, Integer productType, Long productId, Long categoryId, Integer productStatus, Long currentPage, Long pageSize) {
        IPage<ProductListInfoVo> iPage = new Page<>(currentPage, pageSize);
        if (categoryId == null) {
            iPage = baseMapper.listProduct(productId, productName, productType, productStatus, brandName, iPage);
            return PageResult.from(iPage);
        } else {
            List<Long> categoryIds = categoryService.getCategoryIdListByCategoryId(categoryId);
            iPage = baseMapper.listProductWithCategoryIds(productId, productName, productType, productStatus, brandName, categoryIds, iPage);
            return PageResult.from(iPage);
        }
    }

    /**
     * 获取商品详情信息
     *
     * @param id 商品ID
     * @return 商品详情VO
     */
    @Override
    public ProductDetailedVo getProductDetailedVoByProductId(Long id) {
        ProductDetailedVo productDetailedVo = new ProductDetailedVo();
        // 设置商品ID
        productDetailedVo.setProductId(id);
        Product product = lambdaQuery()
                .eq(Product::getId, id)
                .select(
                        Product::getId,
                        Product::getProductName,
                        Product::getProductTip,
                        Product::getBannerImageUrls,
                        Product::getDetailImageUrls,
                        Product::getProductStatus,
                        Product::getProductType,
                        Product::getBrandId
                )
                .one();
        if (product == null) {
            throw new ProductNotExistsException("商品不存在！");
        }
        // 保存浏览历史
        if (UserContext.getId() != null) {
            // 首先查询是否当前浏览过该商品
            LocalDateTime start = LocalDate.now().atStartOfDay();
            LocalDateTime end = LocalDate.now().plusDays(1).atStartOfDay().minusNanos(1);
            Optional<BrowseHistory> optionalBrowseHistory = browseHistoryService
                    .lambdaQuery()
                    .eq(BrowseHistory::getUserId, UserContext.getId())
                    .eq(BrowseHistory::getProductId, id)
                    .ge(BrowseHistory::getBrowseTime, start)
                    .le(BrowseHistory::getBrowseTime, end)
                    .oneOpt();
            // 如果存在，删除该条记录
            optionalBrowseHistory.ifPresent(browseHistory -> browseHistoryService.removeById(browseHistory.getId()));
            // 保存商品的浏览记录
            Long userId = UserContext.getId();
            BrowseHistory browseHistory = new BrowseHistory();
            browseHistory.setProductId(id);
            browseHistory.setBrowseTime(LocalDateTime.now());
            browseHistory.setUserId(userId);
            browseHistoryService.save(browseHistory);
        }
        productDetailedVo.setProductName(product.getProductName());
        productDetailedVo.setProductTip(product.getProductTip());
        productDetailedVo.setProductCarouselImages(Arrays.asList(product.getBannerImageUrls().split(",")));
        productDetailedVo.setProductDetailedImages(Arrays.asList(product.getDetailImageUrls().split(",")));
        productDetailedVo.setProductStatus(product.getProductStatus());
        productDetailedVo.setProductType(product.getProductType());
        productDetailedVo.setBrandId(product.getBrandId());
        List<ProductSpecificationDetailedVo> specificationVoList = new ArrayList<>();
        productSpecificationService
                .lambdaQuery()
                .eq(ProductSpecification::getProductId, product.getId())
                .select(
                        ProductSpecification::getId,
                        ProductSpecification::getAvailableStock,
                        ProductSpecification::getStock,
                        ProductSpecification::getDiscountPrice,
                        ProductSpecification::getPromotionalPrice,
                        ProductSpecification::getOriginalPrice,
                        ProductSpecification::getSpecificationName,
                        ProductSpecification::getSpecificationImageUrl
                )
                .orderByDesc(ProductSpecification::getIsDefault)
                .orderByDesc(ProductSpecification::getSpecificationSort)
                .list()
                .forEach(productSpecification -> {
                    ProductSpecificationDetailedVo productSpecificationDetailedVo = new ProductSpecificationDetailedVo();
                    productSpecificationDetailedVo.setProductSpecificationId(productSpecification.getId());
                    productSpecificationDetailedVo.setStock(Long.valueOf(productSpecification.getStock()));
                    productSpecificationDetailedVo.setAvailableStock(Long.valueOf(productSpecification.getAvailableStock()));
                    productSpecificationDetailedVo.setProductSpecificationName(productSpecification.getSpecificationName());
                    productSpecificationDetailedVo.setProductSpecificationImage(productSpecification.getSpecificationImageUrl());
                    productSpecificationDetailedVo.setProductSpecificationPromotionalPrice(productSpecification.getPromotionalPrice());
                    productSpecificationDetailedVo.setProductSpecificationDiscountPrice(productSpecification.getDiscountPrice());
                    productSpecificationDetailedVo.setProductSpecificationOriginalPrice(productSpecification.getOriginalPrice());
                    specificationVoList.add(productSpecificationDetailedVo);
                });
        productDetailedVo.setProductSpecification(specificationVoList);
        ProductParameter parameter = productParameterService
                .lambdaQuery()
                .eq(ProductParameter::getProductId, product.getId())
                .select(
                        ProductParameter::getManufacturingDate,
                        ProductParameter::getManufacturingEnterprise,
                        ProductParameter::getProductPackaging,
                        ProductParameter::getExpiryDate,
                        ProductParameter::getRegistrationNumber,
                        ProductParameter::getRegistrationIdPhoto,
                        ProductParameter::getMedicalInsuranceNumber
                )
                .one();
        productDetailedVo.setManufacturingDate(parameter.getManufacturingDate());
        productDetailedVo.setExpiryDate(parameter.getExpiryDate());
        productDetailedVo.setManufacturingEnterprise(parameter.getManufacturingEnterprise());
        productDetailedVo.setProductPackaging(parameter.getProductPackaging());
        productDetailedVo.setRegistrationNumber(parameter.getRegistrationNumber());
        productDetailedVo.setRegistrationIdPhoto(parameter.getRegistrationIdPhoto());
        productDetailedVo.setMedicalInsuranceCode(parameter.getMedicalInsuranceNumber());
        Brand brand = brandService
                .lambdaQuery()
                .eq(Brand::getId, product.getBrandId())
                .select(
                        Brand::getBrandName,
                        Brand::getId
                )
                .one();
        if (brand != null) {
            productDetailedVo.setBrandId(brand.getId());
            productDetailedVo.setBrandName(brand.getBrandName());
        }
        productDetailedVo.setDiscountPrice(specificationVoList.getFirst().getProductSpecificationDiscountPrice());
        productDetailedVo.setOriginalPrice(specificationVoList.getFirst().getProductSpecificationOriginalPrice());
        productDetailedVo.setPromotionalPrice(specificationVoList.getFirst().getProductSpecificationPromotionalPrice());
        Long availableStock = 0L;
        Long totalStock = 0L;

        for (ProductSpecificationDetailedVo vo : specificationVoList) {
            availableStock += vo.getAvailableStock();
            totalStock += vo.getStock();
        }
        productDetailedVo.setTotalStock(totalStock);
        productDetailedVo.setAvailableStock(availableStock);
        // 不同类型的商品需要查询不同的讯息
        if (productDetailedVo.getProductType() == ProductType.SECKILL_PRODUCT) {
            // 秒杀商品需要查询秒杀开始时间，秒杀结束时间，以及已抢比例
            Seckill seckill = seckillService
                    .lambdaQuery()
                    .eq(Seckill::getProductId, product.getId())
                    .select(Seckill::getSeckillStartTime, Seckill::getSeckillEndTime)
                    .one();

            ZoneId chinaZone = ZoneId.of("Asia/Shanghai");

            ZonedDateTime futureZonedDateTime = seckill.getSeckillEndTime().atZone(chinaZone);

            ZonedDateTime nowZonedDateTime = ZonedDateTime.now(chinaZone);

            long millisecondsDiff = ChronoUnit.MILLIS.between(nowZonedDateTime, futureZonedDateTime);

            BigDecimal snappedUpRate = new BigDecimal(productDetailedVo.getTotalStock() - productDetailedVo.getAvailableStock())
                    .divide(new BigDecimal(productDetailedVo.getTotalStock()),
                            2, // 保留2位小数
                            RoundingMode.HALF_UP); // 四舍五入
            productDetailedVo.setSeckillEndRemainingMillis(millisecondsDiff);
            productDetailedVo.setSnappedUpRate(snappedUpRate);
        }
        return productDetailedVo;
    }

    @Override
    public OrderItemInfoVo queryOrderPrepareInfo(Long productId, Long productSpecificationId) {
        return baseMapper.queryOrderPrepareInfo(productId, productSpecificationId);
    }


}



